home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / pcl / pcl-rev4.lha / walk.lisp < prev    next >
Text File  |  1990-09-26  |  69KB  |  2,025 lines

  1. ;;;-*- Mode:LISP; Package:(WALKER LISP 1000); Base:10; Syntax:Common-lisp -*-
  2. ;;;
  3. ;;; *************************************************************************
  4. ;;; Copyright (c) 1985, 1986, 1987, 1988, 1989, 1990 Xerox Corporation.
  5. ;;; All rights reserved.
  6. ;;;
  7. ;;; Use and copying of this software and preparation of derivative works
  8. ;;; based upon this software are permitted.  Any distribution of this
  9. ;;; software or derivative works must comply with all applicable United
  10. ;;; States export control laws.
  11. ;;; 
  12. ;;; This software is made available AS IS, and Xerox Corporation makes no
  13. ;;; warranty about the software, its performance or its conformity to any
  14. ;;; specification.
  15. ;;; 
  16. ;;; Any person obtaining a copy of this software is requested to send their
  17. ;;; name and post office or electronic mail address to:
  18. ;;;   CommonLoops Coordinator
  19. ;;;   Xerox PARC
  20. ;;;   3333 Coyote Hill Rd.
  21. ;;;   Palo Alto, CA 94304
  22. ;;; (or send Arpanet mail to CommonLoops-Coordinator.pa@Xerox.arpa)
  23. ;;;
  24. ;;; Suggestions, comments and requests for improvements are also welcome.
  25. ;;; *************************************************************************
  26. ;;; 
  27. ;;; A simple code walker, based IN PART on: (roll the credits)
  28. ;;;   Larry Masinter's Masterscope
  29. ;;;   Moon's Common Lisp code walker
  30. ;;;   Gary Drescher's code walker
  31. ;;;   Larry Masinter's simple code walker
  32. ;;;   .
  33. ;;;   .
  34. ;;;   boy, thats fair (I hope).
  35. ;;;
  36. ;;; For now at least, this code walker really only does what PCL needs it to
  37. ;;; do.  Maybe it will grow up someday.
  38. ;;;
  39.  
  40. ;;;
  41. ;;; This code walker used to be completely portable.  Now it is just "Real
  42. ;;; easy to port".  This change had to happen because the hack that made it
  43. ;;; completely portable kept breaking in different releases of different
  44. ;;; Common Lisps, and in addition it never worked entirely anyways.  So,
  45. ;;; its now easy to port.  To port this walker, all you have to write is one
  46. ;;; simple macro and two simple functions.  These macros and functions are
  47. ;;; used by the walker to manipluate the macroexpansion environments of
  48. ;;; the Common Lisp it is running in.
  49. ;;;
  50. ;;; The code which implements the macroexpansion environment manipulation
  51. ;;; mechanisms is in the first part of the file, the real walker follows it.
  52. ;;; 
  53.  
  54. (in-package 'walker)
  55.  
  56. ;;;
  57. ;;; The user entry points are walk-form and nested-walked-form.  In addition,
  58. ;;; it is legal for user code to call the variable information functions:
  59. ;;; variable-lexical-p, variable-special-p and variable-class.  Some users
  60. ;;; will need to call define-walker-template, they will have to figure that
  61. ;;; out for themselves.
  62. ;;; 
  63. (export '(define-walker-template
  64.       walk-form
  65.       nested-walk-form
  66.       variable-lexical-p
  67.       variable-special-p
  68.       variable-globally-special-p
  69.       *variable-declarations*
  70.       variable-declaration
  71.       ))
  72.  
  73.  
  74.  
  75. ;;;
  76. ;;; On the following pages are implementations of the implementation specific
  77. ;;; environment hacking functions for each of the implementations this walker
  78. ;;; has been ported to.  If you add a new one, so this walker can run in a new
  79. ;;; implementation of Common Lisp, please send the changes back to us so that
  80. ;;; others can also use this walker in that implementation of Common Lisp.
  81. ;;;
  82. ;;; This code just hacks 'macroexpansion environments'.  That is, it is only
  83. ;;; concerned with the function binding of symbols in the environment.  The
  84. ;;; walker needs to be able to tell if the symbol names a lexical macro or
  85. ;;; function, and it needs to be able to build environments which contain
  86. ;;; lexical macro or function bindings.  It must be able, when walking a
  87. ;;; macrolet, flet or labels form to construct an environment which reflects
  88. ;;; the bindings created by that form.  Note that the environment created
  89. ;;; does NOT have to be sufficient to evaluate the body, merely to walk its
  90. ;;; body.  This means that definitions do not have to be supplied for lexical
  91. ;;; functions, only the fact that that function is bound is important.  For
  92. ;;; macros, the macroexpansion function must be supplied.
  93. ;;;
  94. ;;; This code is organized in a way that lets it work in implementations that
  95. ;;; stack cons their environments.  That is reflected in the fact that the
  96. ;;; only operation that lets a user build a new environment is a with-body
  97. ;;; macro which executes its body with the specified symbol bound to the new
  98. ;;; environment.  No code in this walker or in PCL will hold a pointer to
  99. ;;; these environments after the body returns.  Other user code is free to do
  100. ;;; so in implementations where it works, but that code is not considered
  101. ;;; portable.
  102. ;;;
  103. ;;; There are 3 environment hacking tools.  One macro which is used for
  104. ;;; creating new environments, and two functions which are used to access the
  105. ;;; bindings of existing environments.
  106. ;;;
  107. ;;; WITH-AUGMENTED-ENVIRONMENT
  108. ;;;
  109. ;;; ENVIRONMENT-FUNCTION
  110. ;;;
  111. ;;; ENVIRONMENT-MACRO
  112. ;;; 
  113.  
  114. (defun unbound-lexical-function (&rest args)
  115.   (declare (ignore args))
  116.   (error "The evaluator was called to evaluate a form in a macroexpansion~%~
  117.           environment constructed by the PCL portable code walker.  These~%~
  118.           environments are only useful for macroexpansion, they cannot be~%~
  119.           used for evaluation.~%~
  120.           This error should never occur when using PCL.~%~
  121.           This most likely source of this error is a program which tries to~%~
  122.           to use the PCL portable code walker to build its own evaluator."))
  123.  
  124.  
  125. ;;;
  126. ;;; In Coral Common Lisp, the macroexpansion environment is just a list
  127. ;;; of environment entries.  The cadr of each element specifies the type
  128. ;;; of the element.  The only types that interest us are CCL::MACRO and
  129. ;;; FUNCTION.  In these cases the element is interpreted as follows.
  130. ;;;
  131. ;;;   (<function-name> CCL::MACRO . macroexpansion-function)
  132. ;;;   
  133. ;;;   (<function-name> FUNCTION . <fn>)
  134. ;;;   
  135. ;;;   When in the compiler, <fn> is a gensym which will be
  136. ;;;   a variable which bound at run-time to the function.
  137. ;;;   When in the interpreter, <fn> is the actual function.
  138. ;;;   
  139. ;;;
  140. #+:Coral
  141. (progn
  142.  
  143. (defmacro with-augmented-environment
  144.       ((new-env old-env &key functions macros) &body body)
  145.   `(let ((,new-env (with-augmented-environment-internal ,old-env
  146.                             ,functions
  147.                             ,macros)))
  148.      ,@body))
  149.  
  150. (defun with-augmented-environment-internal (env functions macros)
  151.   (dolist (f functions)
  152.     (push (list* f 'function (gensym)) env))
  153.   (dolist (m macros)
  154.     (push (list* (car m) 'ccl::macro (cadr m)) env))
  155.   env)
  156.  
  157. (defun environment-function (env fn)
  158.   (let ((entry (assoc fn env :test #'equal)))
  159.     (and entry
  160.      (eq (cadr entry) 'function)
  161.      (cddr entry))))
  162.  
  163. (defun environment-macro (env macro)
  164.   (let ((entry (assoc macro env :test #'equal)))
  165.     (and entry
  166.      (eq (cadr entry) 'ccl::macro)
  167.      (cddr entry))))
  168.  
  169. );#+:Coral
  170.  
  171.  
  172. ;;;
  173. ;;; Franz Common Lisp is a lot like Coral Lisp.  The macroexpansion
  174. ;;; environment is just a list of entries.  The cadr of each element
  175. ;;; specifies the type of the element.  The types that interest us
  176. ;;; are FUNCTION, EXCL::MACRO, and COMPILER::FUNCTION-VALUE.  These
  177. ;;; are interpreted as follows:
  178. ;;;
  179. ;;;   (<function-name> FUNCTION . <a lexical closure>)
  180. ;;;
  181. ;;;      This happens in the interpreter with lexically
  182. ;;;      bound functions.
  183. ;;;
  184. ;;;   (<function-name> COMPILER::FUNCTION-VALUE . <gensym>)
  185. ;;;
  186. ;;;      This happens in the compiler.  The gensym represents
  187. ;;;      a variable which will be bound at run time to the
  188. ;;;      function object.
  189. ;;;
  190. ;;;   (<function-name> EXCL::MACRO . <a lambda>)
  191. ;;;
  192. ;;;      In both interpreter and compiler, this is the
  193. ;;;      representation used for macro definitions.
  194. ;;;   
  195. ;;;
  196. #+:ExCL
  197. (progn
  198.  
  199. (defmacro with-augmented-environment
  200.       ((new-env old-env &key functions macros) &body body)
  201.   `(let ((,new-env (with-augmented-environment-internal ,old-env
  202.                             ,functions
  203.                             ,macros)))
  204.      ,@body))
  205.  
  206. (defun with-augmented-environment-internal (env functions macros)
  207.   (dolist (f functions)
  208.     (push (list* f 'function #'unbound-lexical-function) env))
  209.   (dolist (m macros)
  210.     (push (list* (car m) 'excl::macro (cadr m)) env))
  211.   env)
  212.  
  213. (defun environment-function (env fn)
  214.   (let ((entry (assoc fn env :test #'equal)))
  215.     (and entry
  216.      (or (eq (cadr entry) 'function)
  217.          (eq (cadr entry) 'compiler::function-value))
  218.      (cddr entry))))
  219.  
  220. (defun environment-macro (env macro)
  221.   (let ((entry (assoc macro env :test #'equal)))
  222.     (and entry
  223.      (eq (cadr entry) 'excl::macro)
  224.      (cddr entry))))
  225.  
  226. );#+:ExCL
  227.  
  228.  
  229. #+Lucid
  230. (progn
  231.   
  232. (proclaim '(inline
  233.         %alphalex-p
  234.         add-contour-to-env-shape
  235.         make-function-variable
  236.         make-sfc-contour
  237.         sfc-contour-type
  238.         sfc-contour-elements
  239.         add-sfc-contour
  240.         add-function-contour
  241.         add-macrolet-contour
  242.         find-variable-in-contour
  243.         find-alist-element-in-contour
  244.         find-macrolet-in-contour))
  245.  
  246. (defun %alphalex-p (object)
  247.   #-Prime
  248.   (eq (cadddr (cddddr object)) 'lucid::%alphalex)
  249.   #+Prime
  250.   (eq (caddr (cddddr object)) 'lucid::%alphalex))
  251.  
  252. #+Prime 
  253. (defun lucid::augment-lexenv-fvars-dummy (lexical vars)
  254.   (lucid::augment-lexenv-fvars-aux lexical vars '() '() 'flet '()))
  255.  
  256. (defconstant function-contour 1)
  257. (defconstant macrolet-contour 5)
  258.  
  259. (defstruct lucid::contour
  260.   type
  261.   elements)
  262.  
  263. (defun add-contour-to-env-shape (contour-type elements env-shape)
  264.   (cons (make-contour :type contour-type
  265.               :elements elements)
  266.     env-shape))
  267.  
  268. (defstruct (variable (:constructor make-variable (name source-type)))
  269.   name
  270.   (identifier nil)
  271.   source-type)
  272.  
  273. (defconstant function-sfc-contour 1)
  274. (defconstant macrolet-sfc-contour 8)
  275. (defconstant function-variable-type 1)
  276.  
  277. (defun make-function-variable (name)
  278.   (make-variable name function-variable-type))
  279.  
  280. (defun make-sfc-contour (type elements)
  281.   (cons type elements))
  282.  
  283. (defun sfc-contour-type (sfc-contour)
  284.   (car sfc-contour))
  285.  
  286. (defun sfc-contour-elements (sfc-contour)
  287.   (cdr sfc-contour))
  288.  
  289. (defun add-sfc-contour (element-list environment type)
  290.   (cons (make-sfc-contour type element-list) environment))
  291.  
  292. (defun add-function-contour (variable-list environment)
  293.   (add-sfc-contour variable-list environment function-sfc-contour))
  294.  
  295. (defun add-macrolet-contour (alist environment)
  296.   (add-sfc-contour alist environment macrolet-sfc-contour))
  297.  
  298. (defun find-variable-in-contour (name contour)
  299.   (dolist (element (sfc-contour-elements contour) nil)
  300.     (when (eq (variable-name element) name)
  301.       (return element))))
  302.  
  303. (defun find-alist-element-in-contour (name contour)
  304.   (cdr (assoc name (sfc-contour-elements contour))))
  305.  
  306. (defun find-macrolet-in-contour (name contour)
  307.   (find-alist-element-in-contour name contour))
  308.  
  309. (defmacro do-sfc-contours ((contour-var environment &optional result)
  310.                &body body)
  311.   `(dolist (,contour-var ,environment ,result) ,@body))
  312.  
  313.  
  314. (defmacro with-augmented-environment
  315.       ((new-env old-env &key functions macros) &body body)     
  316.   `(let* ((,new-env (with-augmented-environment-internal ,old-env
  317.                              ,functions
  318.                              ,macros)))
  319.      ,@body))
  320.  
  321. ;;;
  322. ;;; with-augmented-environment-internal is where the real work of augmenting
  323. ;;; the environment happens.
  324. ;;; 
  325. (defun with-augmented-environment-internal (env functions macros)
  326.   (let ((function-names (mapcar #'first functions))
  327.     (macro-names (mapcar #'first macros))
  328.     (macro-functions (mapcar #'second macros)))
  329.     (cond ((or (null env)
  330.            (contour-p (first env)))
  331.        (when function-names
  332.          (setq env (add-contour-to-env-shape function-contour
  333.                          function-names
  334.                          env)))
  335.        (when macro-names
  336.          (setq env (add-contour-to-env-shape macrolet-contour
  337.                          (pairlis macro-names
  338.                               macro-functions)
  339.                          env))))
  340.       ((%alphalex-p env)
  341.        (when function-names
  342.          (setq env (lucid::augment-lexenv-fvars-dummy env function-names)))
  343.        (when macro-names
  344.          (setq env (lucid::augment-lexenv-mvars env
  345.                             macro-names
  346.                             macro-functions))))
  347.       (t
  348.        (when function-names
  349.          (setq env (add-function-contour
  350.              (mapcar #'make-function-variable function-names)
  351.              env)))
  352.        (when macro-names
  353.          (setq env (add-macrolet-contour
  354.              (pairlis macro-names macro-functions)
  355.              env)))))
  356.     env))
  357.      
  358.  
  359. (defun environment-function (env fn)
  360.   (cond ((null env) nil)
  361.     ((contour-p (first env))
  362.      (if (lucid::find-lexical-function fn env)
  363.          t
  364.          nil))
  365.     ((%alphalex-p env)
  366.      (if (lucid::lexenv-fvar fn env)
  367.          t
  368.          nil))
  369.     (t (do-sfc-contours (contour env nil)
  370.          (let ((type (sfc-contour-type contour)))
  371.            (cond ((eql type function-sfc-contour)
  372.               (when (find-variable-in-contour fn contour)
  373.             (return t)))
  374.              ((eql type macrolet-sfc-contour)
  375.               (when (find-macrolet-in-contour fn contour)
  376.             (return nil)))))))))
  377.               
  378. (defun environment-macro (env macro)
  379.   (cond ((null env) nil)
  380.     ((contour-p (first env))
  381.      (lucid::find-lexical-macro macro env))
  382.     ((%alphalex-p env)
  383.      (lucid::lexenv-mvar macro env))
  384.     (t (do-sfc-contours (contour env nil)
  385.          (let ((type (sfc-contour-type contour)))
  386.            (cond ((eql type function-sfc-contour)
  387.               (when (find-variable-in-contour macro contour)
  388.             (return nil)))
  389.              ((eql type macrolet-sfc-contour)
  390.               (let ((fn (find-macrolet-in-contour macro contour)))
  391.             (when fn
  392.               (return fn))))))))))
  393.   
  394.  
  395. );#+Lucid
  396.  
  397.  
  398.  
  399. ;;;
  400. ;;; On the 3600, the documentation for how the environments are represented
  401. ;;; is in sys:sys;eval.lisp.  That total information is not repeated here.
  402. ;;; The important points are that:
  403. ;;;    si:env-variables returns a list of which each element is:
  404. ;;;
  405. ;;;        (symbol value)
  406. ;;;         or (symbol . locative)
  407. ;;;
  408. ;;;    The first form is for lexical variables, the second for
  409. ;;;    special and instance variables.  In either case CADR of
  410. ;;;    the entry is the value and SETF of CADR is used to change
  411. ;;;    the value.  Variables are looked up with ASSQ.
  412. ;;;
  413. ;;;    si:env-functions returns a list of which each element is:
  414. ;;;     
  415. ;;;        (symbol definition)
  416. ;;;
  417. ;;;    where definition is anything that could go in a function cell.
  418. ;;;    This is used for both local functions and local macros.
  419. ;;;
  420. ;;; The 3600 stack conses its environments (at least in the interpreter).
  421. ;;; This means that code written using this walker and running on the 3600
  422. ;;; must not hold on to the environment after the walk-function returns.
  423. ;;; No code in this walker or in PCL does that.
  424. ;;;
  425. #+Genera
  426. (progn
  427.  
  428. (defmacro with-augmented-environment
  429.       ((new-env old-env &key functions macros) &body body)
  430.   (let ((funs (make-symbol "FNS"))
  431.     (macs (make-symbol "MACROS"))
  432.     (new  (make-symbol "NEW")))
  433.     `(let ((,funs ,functions)
  434.        (,macs ,macros)
  435.        (,new ()))
  436.        (dolist (f ,funs)
  437.      (push `(,(car f) ,#'unbound-lexical-function) ,new))
  438.        (dolist (m ,macs)
  439.      (push `(,(car m) (special ,(cadr m))) ,new))
  440.        (let* ((.old-env. ,old-env)
  441.           (.old-vars. (pop .old-env.))
  442.           (.old-funs. (pop .old-env.))
  443.           (.old-blks. (pop .old-env.))
  444.           (.old-tags. (pop .old-env.))
  445.           (.old-dcls. (pop .old-env.)))
  446.      (si:with-interpreter-environment (,new-env
  447.                        .old-env.
  448.                        .old-vars.
  449.                        (append ,new .old-funs.)
  450.                        .old-blks.
  451.                        .old-tags.
  452.                        .old-dcls.)
  453.        ,@body)))))
  454.   
  455.  
  456. (defun environment-function (env fn)
  457.   (if (null env)
  458.       (values nil nil)
  459.       (let ((entry (assoc fn (si:env-functions env) :test #'equal)))
  460.     (if (and entry
  461.          (or (not (listp (cadr entry)))
  462.              (not (eq (caadr entry) 'special))))
  463.         (values (cadr entry) t)
  464.         (environment-function (si:env-parent env) fn)))))
  465.  
  466. (defun environment-macro (env macro)
  467.   (if (null env)
  468.       (values nil nil)
  469.       (let ((entry (assoc macro (si:env-functions env) :test #'equal)))
  470.     (if (and entry
  471.          (listp (cadr entry))
  472.          (eq (caadr entry) 'special))
  473.         (values (cadadr entry) t)
  474.         (environment-macro (si:env-parent env) macro)))))
  475.  
  476. );#+Genera
  477.  
  478. #+Cloe-Runtime
  479. (progn
  480.  
  481. (defmacro with-augmented-environment
  482.       ((new-env old-env &key functions macros) &body body)
  483.   `(let ((,new-env (with-augmented-environment-internal ,old-env ,functions ,macros)))
  484.      ,@body))
  485.  
  486. (defun with-augmented-environment-internal (env functions macros)
  487.   functions
  488.   (dolist (m macros)
  489.     (setf env `(,(first m) (compiler::macro . ,(second m)) ,@env)))
  490.   env)
  491.  
  492. (defun environment-function (env fn)
  493.   nil)
  494.  
  495. (defun environment-macro (env macro)
  496.   (let ((entry (getf env macro)))
  497.     (if (and (consp entry)
  498.          (eq (car entry) 'compiler::macro))
  499.     (values (cdr entry) t)
  500.     (values nil nil))))
  501.  
  502. );#+Cloe-Runtime
  503.  
  504.  
  505. ;;;
  506. ;;; In Xerox Lisp, the compiler and interpreter use different structures for
  507. ;;; the environment.  This doesn't cause a serious problem, the parts of the
  508. ;;; environments we are concerned with are fairly similar.
  509. ;;; 
  510. #+:Xerox
  511. (progn
  512.  
  513. (defmacro with-augmented-environment
  514.       ((new-env old-env &key functions macros) &body body)     
  515.   `(let* ((,new-env (with-augmented-environment-internal ,old-env
  516.                              ,functions
  517.                              ,macros)))
  518.      ,@body))
  519.  
  520. ;;;
  521. ;;; with-augmented-environment-internal is where the real work of augmenting
  522. ;;; the environment happens.  Before it gets there, env had better not be NIL
  523. ;;; anymore because we have to know what kind of environment we are supposed
  524. ;;; to be building up.  This is probably never a real concern in practice.
  525. ;;; It better not be because we don't do anything about it.
  526. ;;; 
  527. (defun with-augmented-environment-internal (env functions macros)
  528.   (cond
  529.      ((compiler::env-p env)
  530.     (dolist (f functions)
  531.        (setq env (compiler::copy-env-with-function
  532.                env f :function)))
  533.     (dolist (m macros)
  534.        (setq env (compiler::copy-env-with-function
  535.            env (car m) :macro (cadr m)))))
  536.      (t (setq env (if (il:environment-p env)
  537.             (il:\\copy-environment env)
  538.             (il:\\make-environment)))
  539.     ;; The functions field of the environment is a plist of function names
  540.     ;; and conses like (:function . fn) or (:macro . expansion-fn).
  541.     ;; Note that we can't smash existing entries in this plist since these
  542.     ;; are likely shared with older environments.
  543.     (dolist (f functions)
  544.       (setf (il:environment-functions env)
  545.         (list* f (cons :function #'unbound-lexical-function)
  546.                (il:environment-functions env))))
  547.     (dolist (m macros)
  548.       (setf (il:environment-functions env)
  549.         (list* (car m) (cons :macro (cadr m))
  550.                (il:environment-functions env))))))
  551.   env)
  552.  
  553. (defun environment-function (env fn)
  554.   (cond ((compiler::env-p env) (eq (compiler:env-fboundp env fn) :function))
  555.     ((il:environment-p env) (eq (getf (il:environment-functions env) fn)
  556.                     :function))
  557.     (t nil)))
  558.  
  559. (defun environment-macro (env macro) 
  560.   (cond ((compiler::env-p env)
  561.      (multiple-value-bind (type def)
  562.          (compiler:env-fboundp env macro)
  563.        (when (eq type :macro) def)))
  564.     ((il:environment-p env)
  565.      (xcl:destructuring-bind (type . def)
  566.          (getf (il:environment-functions env) macro)
  567.        (when (eq type :macro) def)))
  568.     (t nil)))
  569.  
  570. );#+:Xerox
  571.  
  572.  
  573. ;;;
  574. ;;; In IBUKI Common Lisp, the macroexpansion environment is a three element
  575. ;;; list.  The second element describes lexical functions and macros.  The 
  576. ;;; function entries in this list have the form 
  577. ;;;     (<name> . (FUNCTION . (<function-value> . nil))
  578. ;;; The macro entries have the form 
  579. ;;;     (<name> . (MACRO . (<macro-value> . nil)).
  580. ;;;
  581. ;;;
  582. #+(or KCL IBCL)
  583. (progn
  584.  
  585. (defmacro with-augmented-environment
  586.       ((new-env old-env &key functions macros) &body body)
  587.       `(let ((,new-env (with-augmented-environment-internal ,old-env
  588.                                 ,functions
  589.                                 ,macros)))
  590.          ,@body))
  591.  
  592. (defun with-augmented-environment-internal (env functions macros)
  593.   (let ((first (first env))
  594.     (lexicals (second env))
  595.     (third (third env)))
  596.     (dolist (f functions)
  597.       (push `(,(car f) .  (function  . (,#'unbound-lexical-function . nil)))
  598.         lexicals))
  599.     (dolist (m macros)
  600.       (push `(,(car m)  .  (macro . ( ,(cadr m) . nil))) 
  601.         lexicals))
  602.     (list first lexicals third)))
  603.  
  604. (defun environment-function (env fn)
  605.   (when env
  606.     (let ((entry (assoc fn (second env))))
  607.       (and entry
  608.            (eq (cadr entry) 'function)
  609.            (caddr entry)))))
  610.  
  611. (defun environment-macro (env macro)
  612.   (when env
  613.     (let ((entry (assoc macro (second env))))
  614.       (and entry
  615.            (eq (cadr entry) 'macro)
  616.            (caddr entry)))))
  617. );#+(or KCL IBCL)
  618.  
  619.  
  620. ;;;   --- TI Explorer --
  621.  
  622. ;;; An environment is a two element list, whose car we can ignore and
  623. ;;; whose cadr is list of the local-definitions-frames. Each
  624. ;;; local-definitions-frame holds either macros or functions, but not
  625. ;;; both.  Each frame is a plist of <name> <def> <name> <def> ...  where
  626. ;;; <name> is a locative to the function cell of the symbol that names
  627. ;;; the function or macro, and <def> is the new def or NIL if this is function
  628. ;;; redefinition or (cons 'ticl:macro <macro-expansion-function>) if this is a macro
  629. ;;; redefinition.
  630. ;;;
  631. ;;; Here's an example.  For the form:
  632. ;;; (defun foo ()
  633. ;;;   (macrolet ((bar (a b) (list a b))
  634. ;;;             (bar2 (a b) (list a b)))
  635. ;;;     (flet ((some-local-fn (c d) (print (list c d)))
  636. ;;;           (another (c d) (print (list c d))))
  637. ;;;       (bar (some-local-fn 1 2) 3))))
  638.  
  639. ;;; the environment arg to macroexpand-1 when called on
  640. ;;; (bar (some-local-fn 1 2) 3)
  641. ;;;is 
  642. ;;;(NIL ((#<DTP-LOCATIVE 4710602> NIL
  643. ;;;       #<DTP-LOCATIVE 4710671> NIL)
  644. ;;;      (#<DTP-LOCATIVE 7346562>
  645. ;;;       (TICL:MACRO TICL:NAMED-LAMBDA (BAR (:DESCRIPTIVE-ARGLIST (A B)))
  646. ;;;           (SYS::*MACROARG* &OPTIONAL SYS::*MACROENVIRONMENT*)
  647. ;;;           (BLOCK BAR ....))
  648. ;;;       #<DTP-LOCATIVE 4710664>
  649. ;;;       (TICL:MACRO TICL:NAMED-LAMBDA (BAR2 (:DESCRIPTIVE-ARGLIST (A B)))
  650. ;;;           (SYS::*MACROARG* &OPTIONAL SYS::*MACROENVIRONMENT*)
  651. ;;;           (BLOCK BAR2 ....))))
  652. #+TI
  653. (progn 
  654.  
  655. ;;; from sys:site;macros.lisp
  656. (eval-when (compile load eval)
  657.   
  658. (DEFMACRO MACRO-DEF? (thing)
  659.   `(AND (CONSP ,thing) (EQ (CAR ,thing) 'TICL::MACRO)))
  660.  
  661. ;; the following macro generates code to check the 'local' environment
  662. ;; for a macro definition for THE SYMBOL <name>. Such a definition would
  663. ;; be set up only by a MACROLET. If a macro definition for <name> is
  664. ;; found, its expander function is returned.
  665.  
  666. (DEFMACRO FIND-LOCAL-DEFINITION (name local-function-environment)
  667.   `(IF ,local-function-environment
  668.        (LET ((vcell (ticl::LOCF (SYMBOL-FUNCTION ,name))))
  669.      (DOLIST (frame  ,local-function-environment)
  670.        ;; <value> is nil or a locative
  671.        (LET ((value (sys::GET-LOCATION-OR-NIL (ticl::LOCF frame)
  672.                           vcell))) 
  673.          (When value (RETURN (CAR value))))))
  674.        nil)))
  675.  
  676.  
  677. ;;;Edited by Reed Hastings         13 Jan 88  16:29
  678. (defun environment-macro (env macro)
  679.   "returns what macro-function would, ie. the expansion function"
  680.   ;;some code picked off macroexpand-1
  681.   (let* ((local-definitions (cadr env))
  682.      (local-def (find-local-definition macro local-definitions)))
  683.     (if (macro-def? local-def)
  684.     (cdr local-def))))
  685.  
  686. ;;;Edited by Reed Hastings         13 Jan 88  16:29
  687. ;;;Edited by Reed Hastings         7 Mar 88  19:07
  688. (defun environment-function (env fn)
  689.   (let* ((local-definitions (cadr env)))
  690.     (dolist (frame local-definitions)
  691.       (let ((val (getf frame
  692.                (ticl::locf (symbol-function fn))
  693.                :not-found-marker)))
  694.     (cond ((eq val :not-found-marker))
  695.           ((functionp val) (return t))
  696.           ((and (listp val)
  697.             (eq (car val) 'ticl::macro))
  698.            (return nil))
  699.           (t
  700.            (error "we are confused")))))))
  701.          
  702.  
  703. ;;;Edited by Reed Hastings         13 Jan 88  16:29
  704. ;;;Edited by Reed Hastings         7 Mar 88  19:07
  705. (defun with-augmented-environment-internal (env functions macros)
  706.   (let ((local-definitions (cadr env))
  707.     (new-local-fns-frame
  708.       (mapcan #'(lambda (fn)
  709.               (list (ticl:locf (symbol-function (car fn)))
  710.                 #'unbound-lexical-function))
  711.           functions))
  712.      (new-local-macros-frame
  713.        (mapcan #'(lambda (m)
  714.                (list (ticl:locf (symbol-function (car m))) (cons 'ticl::macro (cadr m))))
  715.            macros)))
  716.     (when new-local-fns-frame 
  717.       (push new-local-fns-frame local-definitions))
  718.     (when new-local-macros-frame
  719.       (push new-local-macros-frame local-definitions))   
  720.     `(,(car env) ,local-definitions)))
  721.  
  722.  
  723. ;;;Edited by Reed Hastings         7 Mar 88  19:07
  724. (defmacro with-augmented-environment
  725.       ((new-env old-env &key functions macros) &body body)
  726.   `(let ((,new-env (with-augmented-environment-internal ,old-env
  727.                             ,functions
  728.                             ,macros)))
  729.      ,@body))
  730.  
  731. );#+TI
  732.  
  733.  
  734. #+(and dec vax common)
  735. (progn
  736.  
  737. (defmacro with-augmented-environment
  738.       ((new-env old-env &key functions macros) &body body)
  739.   `(let ((,new-env (with-augmented-environment-internal ,old-env
  740.                             ,functions
  741.                             ,macros)))
  742.      ,@body))
  743.  
  744. (defun with-augmented-environment-internal (env functions macros)
  745.   #'(lambda (op &optional (arg nil arg-p))
  746.       (cond ((eq op :macro-function) 
  747.          (unless arg-p (error "Invalid environment use."))
  748.          (lookup-macro-function arg env functions macros))
  749.             (arg-p
  750.          (error "Invalid environment operation: ~S ~S" op arg))
  751.             (t
  752.          (lookup-macro-function op env functions macros)))))
  753.  
  754. (defun lookup-macro-function (name env fns macros)
  755.   (let ((m (assoc name macros)))
  756.     (cond (m                (cadr m))
  757.           ((assoc name fns) :function)
  758.           (env              (funcall env name))
  759.           (t                nil))))
  760.  
  761. (defun environment-macro (env macro)
  762.   (let ((m (and env (funcall env macro))))
  763.     (and (not (eq m :function)) 
  764.          m)))
  765.  
  766. ;;; Nobody calls environment-function.  What would it return, anyway?
  767. );#+(and dec vax common)
  768.  
  769.  
  770. ;;;
  771. ;;; In Golden Common Lisp, the macroexpansion environment is just a list
  772. ;;; of environment entries.  Unless the car of the list is :compiler-menv 
  773. ;;; it is an interpreted environment.  The cadr of each element specifies 
  774. ;;; the type of the element.  The only types that interest us are GCL:MACRO
  775. ;;; and FUNCTION.  In these cases the element is interpreted as follows.
  776. ;;;
  777. ;;; Compiled:
  778. ;;;   (<function-name> <gensym> macroexpansion-function)
  779. ;;;   (<function-name> <fn>)
  780. ;;;   
  781. ;;; Interpreted:
  782. ;;;   (<function-name> GCL:MACRO macroexpansion-function)
  783. ;;;   (<function-name> <fn>)
  784. ;;;   
  785. ;;;   When in the compiler, <fn> is a gensym which will be
  786. ;;;   a variable which bound at run-time to the function.
  787. ;;;   When in the interpreter, <fn> is the actual function.
  788. ;;;   
  789. ;;;
  790. #+gclisp
  791. (progn
  792.  
  793. (defmacro with-augmented-environment
  794.       ((new-env old-env &key functions macros) &body body)
  795.   `(let ((,new-env (with-augmented-environment-internal ,old-env
  796.                             ,functions
  797.                             ,macros)))
  798.      ,@body))
  799.  
  800. (defun with-augmented-environment-internal (env functions macros)
  801.   (let ((new-entries nil))
  802.     (dolist (f functions)
  803.       (push (cons (car f) nil) new-entries))
  804.     (dolist (m macros)
  805.       (push (cons (car m)
  806.           (if (eq :compiler-menv (car env))
  807.               (if (eq (caadr m) 'lisp::lambda)
  808.               `(,(gensym) ,(cadr m))
  809.             `(,(gensym) ,@(cadr m)))
  810.             `(gclisp:MACRO ,@(cadr m))))
  811.           new-entries))
  812.     (if (eq :compiler-menv (car env))
  813.     `(:compiler-menv ,@new-entries ,@(cdr env))
  814.       (append new-entries env))))
  815.  
  816. (defun environment-function (env fn)
  817.   (let ((entry (lisp::lexical-function fn env)))
  818.     (and entry 
  819.      (eq entry 'lisp::lexical-function)
  820.      fn)))
  821.  
  822. (defun environment-macro (env macro)
  823.   (let ((entry (assoc macro (if (eq :compiler-menv (first env))
  824.                  (rest env)
  825.                    env))))
  826.     (and entry
  827.      (consp entry)
  828.      (symbolp (car entry))            ;name
  829.      (symbolp (cadr entry))            ;gcl:macro or gensym
  830.      (nthcdr 2 entry))))
  831.  
  832. );#+gclisp
  833.  
  834.  
  835.  
  836. (defmacro with-new-definition-in-environment
  837.       ((new-env old-env macrolet/flet/labels-form) &body body)
  838.   (let ((functions (make-symbol "Functions"))
  839.     (macros (make-symbol "Macros")))
  840.     `(let ((,functions ())
  841.        (,macros ()))
  842.        (ecase (car ,macrolet/flet/labels-form)
  843.      ((flet labels)
  844.       (dolist (fn (cadr ,macrolet/flet/labels-form))
  845.         (push fn ,functions)))
  846.      ((macrolet)
  847.       (dolist (mac (cadr ,macrolet/flet/labels-form))
  848.         (push (list (car mac)
  849.             (convert-macro-to-lambda (cadr mac)
  850.                          (cddr mac)
  851.                          (string (car mac))))
  852.           ,macros))))
  853.        (with-augmented-environment
  854.           (,new-env ,old-env :functions ,functions :macros ,macros)
  855.      ,@body))))
  856.  
  857. #-Genera
  858. (defun convert-macro-to-lambda (llist body &optional (name "Dummy Macro"))
  859.   (let ((gensym (make-symbol name)))
  860.     (eval `(defmacro ,gensym ,llist ,@body))
  861.     (macro-function gensym)))
  862.  
  863. #+Genera
  864. (defun convert-macro-to-lambda (llist body &optional (name "Dummy Macro"))
  865.   (si:defmacro-1
  866.     'sys:named-lambda 'sys:special (make-symbol name) llist body))
  867.  
  868.  
  869.  
  870.  
  871.  
  872. ;;;
  873. ;;; Now comes the real walker.
  874. ;;;
  875. ;;; As the walker walks over the code, it communicates information to itself
  876. ;;; about the walk.  This information includes the walk function, variable
  877. ;;; bindings, declarations in effect etc.  This information is inherently
  878. ;;; lexical, so the walker passes it around in the actual environment the
  879. ;;; walker passes to macroexpansion functions.  This is what makes the
  880. ;;; nested-walk-form facility work properly.
  881. ;;;
  882. (defmacro walker-environment-bind ((var env &rest key-args)
  883.                       &body body)
  884.   `(with-augmented-environment
  885.      (,var ,env :macros (walker-environment-bind-1 ,env ,.key-args))
  886.      .,body))
  887.  
  888. (defvar *key-to-walker-environment* (gensym))
  889.  
  890. (defun env-lock (env)
  891.   (environment-macro env *key-to-walker-environment*))
  892.  
  893. (defun walker-environment-bind-1 (env &key (walk-function nil wfnp)
  894.                        (walk-form nil wfop)
  895.                        (declarations nil decp)
  896.                        (lexical-variables nil lexp))
  897.   (let ((lock (environment-macro env *key-to-walker-environment*)))
  898.     (list
  899.       (list *key-to-walker-environment*
  900.         (list (if wfnp walk-function     (car lock))
  901.           (if wfop walk-form         (cadr lock))
  902.           (if decp declarations      (caddr lock))
  903.           (if lexp lexical-variables (cadddr lock)))))))
  904.           
  905. (defun env-walk-function (env)
  906.   (car (env-lock env)))
  907.  
  908. (defun env-walk-form (env)
  909.   (cadr (env-lock env)))
  910.  
  911. (defun env-declarations (env)
  912.   (caddr (env-lock env)))
  913.  
  914. (defun env-lexical-variables (env)
  915.   (cadddr (env-lock env)))
  916.  
  917.  
  918. (defun note-declaration (declaration env)
  919.   (let ((lock (env-lock env)))
  920.     (setf (caddr lock)
  921.       (cons declaration (caddr lock)))))
  922.  
  923. (defun note-lexical-binding (thing env)
  924.   (let ((lock (env-lock env)))
  925.     (setf (cadddr lock)
  926.       (cons thing (cadddr lock)))))
  927.  
  928.  
  929. (defun VARIABLE-LEXICAL-P (var env)
  930.   (member var (env-lexical-variables env)))
  931.  
  932. (defvar *VARIABLE-DECLARATIONS* '(special))
  933.  
  934. (defun VARIABLE-DECLARATION (declaration var env)
  935.   (if (not (member declaration *variable-declarations*))
  936.       (error "~S is not a reckognized variable declaration." declaration)
  937.       (let ((id (or (member var (env-lexical-variables env)) var)))
  938.     (dolist (decl (env-declarations env))
  939.       (when (and (eq (car decl) declaration)
  940.              (eq (cadr decl) id))
  941.         (return decl))))))
  942.  
  943. (defun VARIABLE-SPECIAL-P (var env)
  944.   (or (not (null (variable-declaration 'special var env)))
  945.       (variable-globally-special-p var)))
  946.  
  947. ;;;
  948. ;;; VARIABLE-GLOBALLY-SPECIAL-P is used to ask if a variable has been
  949. ;;; declared globally special.  Any particular CommonLisp implementation
  950. ;;; should customize this function accordingly and send their customization
  951. ;;; back.
  952. ;;;
  953. ;;; The default version of variable-globally-special-p is probably pretty
  954. ;;; slow, so it uses *globally-special-variables* as a cache to remember
  955. ;;; variables that it has already figured out are globally special.
  956. ;;;
  957. ;;; This would need to be reworked if an unspecial declaration got added to
  958. ;;; Common Lisp.
  959. ;;;
  960. ;;; Common Lisp nit:
  961. ;;;   variable-globally-special-p should be defined in Common Lisp.
  962. ;;;
  963. #-(or Genera Cloe-Runtime Lucid Xerox Excl KCL IBCL (and dec vax common) :CMU HP-HPLabs
  964.       GCLisp TI pyramid)
  965. (defvar *globally-special-variables* ())
  966.  
  967. (defun variable-globally-special-p (symbol)
  968.   #+Genera                      (si:special-variable-p symbol)
  969.   #+Cloe-Runtime        (compiler::specialp symbol)
  970.   #+Lucid                       (lucid::proclaimed-special-p symbol)
  971.   #+TI                          (get symbol 'special)
  972.   #+Xerox                       (il:variable-globally-special-p symbol)
  973.   #+(and dec vax common)        (get symbol 'system::globally-special)
  974.   #+(or KCL IBCL)               (si:specialp symbol)
  975.   #+excl                        (get symbol 'excl::.globally-special.)
  976.   #+:CMU            (or (get symbol 'lisp::globally-special)
  977.                     (get symbol
  978.                      'clc::globally-special-in-compiler))
  979.   #+HP-HPLabs                   (member (get symbol 'impl:vartype)
  980.                     '(impl:fluid impl:global)
  981.                     :test #'eq)
  982.   #+:GCLISP                     (gclisp::special-p symbol)
  983.   #+pyramid            (or (get symbol 'lisp::globally-special)
  984.                     (get symbol
  985.                      'clc::globally-special-in-compiler))
  986.   #+:CORAL                      (ccl::proclaimed-special-p symbol)
  987.   #-(or Genera Cloe-Runtime Lucid Xerox Excl KCL IBCL (and dec vax common) :CMU HP-HPLabs
  988.     GCLisp TI pyramid :CORAL)
  989.   (or (not (null (member symbol *globally-special-variables* :test #'eq)))
  990.       (when (eval `(flet ((ref () ,symbol))
  991.              (let ((,symbol '#,(list nil)))
  992.                (and (boundp ',symbol) (eq ,symbol (ref))))))
  993.     (push symbol *globally-special-variables*)
  994.     t)))
  995.  
  996.  
  997.   ;;   
  998. ;;;;;; Handling of special forms (the infamous 24).
  999.   ;;
  1000. ;;;
  1001. ;;; and I quote...
  1002. ;;; 
  1003. ;;;     The set of special forms is purposely kept very small because
  1004. ;;;     any program analyzing program (read code walker) must have
  1005. ;;;     special knowledge about every type of special form. Such a
  1006. ;;;     program needs no special knowledge about macros...
  1007. ;;;
  1008. ;;; So all we have to do here is a define a way to store and retrieve
  1009. ;;; templates which describe how to walk the 24 special forms and we are all
  1010. ;;; set...
  1011. ;;;
  1012. ;;; Well, its a nice concept, and I have to admit to being naive enough that
  1013. ;;; I believed it for a while, but not everyone takes having only 24 special
  1014. ;;; forms as seriously as might be nice.  There are (at least) 3 ways to
  1015. ;;; lose:
  1016. ;;
  1017. ;;;   1 - Implementation x implements a Common Lisp special form as a macro
  1018. ;;;       which expands into a special form which:
  1019. ;;;         - Is a common lisp special form (not likely)
  1020. ;;;         - Is not a common lisp special form (on the 3600 IF --> COND).
  1021. ;;;
  1022. ;;;     * We can safe ourselves from this case (second subcase really) by
  1023. ;;;       checking to see if there is a template defined for something
  1024. ;;;       before we check to see if we we can macroexpand it.
  1025. ;;;
  1026. ;;;   2 - Implementation x implements a Common Lisp macro as a special form.
  1027. ;;;
  1028. ;;;     * This is a screw, but not so bad, we save ourselves from it by
  1029. ;;;       defining extra templates for the macros which are *likely* to
  1030. ;;;       be implemented as special forms.  (DO, DO* ...)
  1031. ;;;
  1032. ;;;   3 - Implementation x has a special form which is not on the list of
  1033. ;;;       Common Lisp special forms.
  1034. ;;;
  1035. ;;;     * This is a bad sort of a screw and happens more than I would like
  1036. ;;;       to think, especially in the implementations which provide more
  1037. ;;;       than just Common Lisp (3600, Xerox etc.).
  1038. ;;;       The fix is not terribly staisfactory, but will have to do for
  1039. ;;;       now.  There is a hook in get walker-template which can get a
  1040. ;;;       template from the implementation's own walker.  That template
  1041. ;;;       has to be converted, and so it may be that the right way to do
  1042. ;;;       this would actually be for that implementation to provide an
  1043. ;;;       interface to its walker which looks like the interface to this
  1044. ;;;       walker.
  1045. ;;;
  1046.  
  1047. (eval-when (compile load eval)
  1048.  
  1049. (defmacro get-walker-template-internal (x) ;Has to be inside eval-when because
  1050.   `(get ,x 'walker-template))           ;Golden Common Lisp doesn't hack
  1051.                        ;compile time definition of macros
  1052.                        ;right for setf.
  1053.  
  1054. (defmacro define-walker-template
  1055.       (name &optional (template '(nil repeat (eval))))
  1056.   `(eval-when (load eval)
  1057.      (setf (get-walker-template-internal ',name) ',template)))
  1058. )
  1059.  
  1060. (defun get-walker-template (x)
  1061.   (cond ((symbolp x)
  1062.      (or (get-walker-template-internal x)
  1063.          (get-implementation-dependent-walker-template x)))
  1064.     ((and (listp x) (eq (car x) 'lambda))
  1065.      '(lambda repeat (eval)))
  1066.     (t
  1067.      (error "Can't get template for ~S" x))))
  1068.  
  1069. (defun get-implementation-dependent-walker-template (x)
  1070.   (declare (ignore x))
  1071.   ())
  1072.  
  1073.  
  1074.   ;;   
  1075. ;;;;;; The actual templates
  1076.   ;;   
  1077.  
  1078. (define-walker-template BLOCK                (NIL NIL REPEAT (EVAL)))
  1079. (define-walker-template CATCH                (NIL EVAL REPEAT (EVAL)))
  1080. (define-walker-template COMPILER-LET         walk-compiler-let)
  1081. (define-walker-template DECLARE              walk-unexpected-declare)
  1082. (define-walker-template EVAL-WHEN            (NIL QUOTE REPEAT (EVAL)))
  1083. (define-walker-template FLET                 walk-flet)
  1084. (define-walker-template FUNCTION             (NIL CALL))
  1085. (define-walker-template GO                   (NIL QUOTE))
  1086. (define-walker-template IF                   walk-if)
  1087. (define-walker-template LABELS               walk-labels)
  1088. (define-walker-template LAMBDA               walk-lambda)
  1089. (define-walker-template LET                  walk-let)
  1090. (define-walker-template LET*                 walk-let*)
  1091. (define-walker-template MACROLET          ta walk-macrolet)
  1092. (define-walker-template MULTIPLE-VALUE-CALL  (NIL EVAL REPEAT (EVAL)))
  1093. (define-walker-template MULTIPLE-VALUE-PROG1 (NIL RETURN REPEAT (EVAL)))
  1094. (define-walker-template MULTIPLE-VALUE-SETQ  (NIL (REPEAT (SET)) EVAL))
  1095. (define-walker-template MULTIPLE-VALUE-BIND  walk-multiple-value-bind)
  1096. (define-walker-template PROGN                (NIL REPEAT (EVAL)))
  1097. (define-walker-template PROGV                (NIL EVAL EVAL REPEAT (EVAL)))
  1098. (define-walker-template QUOTE                (NIL QUOTE))
  1099. (define-walker-template RETURN-FROM          (NIL QUOTE REPEAT (RETURN)))
  1100. (define-walker-template SETQ                 (NIL REPEAT (SET EVAL)))
  1101. (define-walker-template TAGBODY              walk-tagbody)
  1102. (define-walker-template THE                  (NIL QUOTE EVAL))
  1103. (define-walker-template THROW                (NIL EVAL EVAL))
  1104. (define-walker-template UNWIND-PROTECT       (NIL RETURN REPEAT (EVAL)))
  1105.  
  1106. ;;; The new special form.
  1107. ;(define-walker-template pcl::LOAD-TIME-EVAL       (NIL EVAL))
  1108.  
  1109. ;;;
  1110. ;;; And the extra templates...
  1111. ;;;
  1112. (define-walker-template DO      walk-do)
  1113. (define-walker-template DO*     walk-do*)
  1114. (define-walker-template PROG    walk-prog)
  1115. (define-walker-template PROG*   walk-prog*)
  1116. (define-walker-template COND    (NIL REPEAT ((TEST REPEAT (EVAL)))))
  1117.  
  1118. #+Genera
  1119. (progn
  1120.   (define-walker-template zl::named-lambda walk-named-lambda)
  1121.   (define-walker-template SCL:LETF walk-let)
  1122.   (define-walker-template SCL:LETF* walk-let*)
  1123.   )
  1124.  
  1125. #+Lucid
  1126. (progn
  1127.   (define-walker-template #+LCL3.0 lucid-common-lisp:named-lambda
  1128.               #-LCL3.0 sys:named-lambda walk-named-lambda)
  1129.   )
  1130.  
  1131. #+(or KCL IBCL)
  1132. (progn
  1133.   (define-walker-template lambda-block walk-named-lambda);Not really right,
  1134.                              ;we don't hack block
  1135.                                  ;names anyways.
  1136.   )
  1137.  
  1138. #+TI
  1139. (progn
  1140.   (define-walker-template TICL::LET-IF walk-let-if)
  1141.   )
  1142.  
  1143. #+:Coral
  1144. (progn
  1145.   (define-walker-template ccl:%stack-block walk-let)
  1146.   )
  1147.  
  1148.  
  1149.  
  1150. (defun WALK-FORM (form
  1151.           &optional environment
  1152.                 (walk-function
  1153.                   #'(lambda (subform context env)
  1154.                   (declare (ignore context env))
  1155.                   subform)))
  1156.   (walker-environment-bind (new-env environment :walk-function walk-function)
  1157.     (walk-form-internal form :eval new-env)))
  1158.  
  1159. ;;;
  1160. ;;; nested-walk-form provides an interface that allows nested macros, each
  1161. ;;; of which must walk their body to just do one walk of the body of the
  1162. ;;; inner macro.  That inner walk is done with a walk function which is the
  1163. ;;; composition of the two walk functions.
  1164. ;;;
  1165. ;;; This facility works by having the walker annotate the environment that
  1166. ;;; it passes to macroexpand-1 to know which form is being macroexpanded.
  1167. ;;; If then the &whole argument to the macroexpansion function is eq to
  1168. ;;; the env-walk-form of the environment, nested-walk-form can be certain
  1169. ;;; that there are no intervening layers and that a nested walk is alright.
  1170. ;;;
  1171. ;;; There are some semantic problems with this facility.  In particular, if
  1172. ;;; the outer walk function returns T as its walk-no-more-p value, this will
  1173. ;;; prevent the inner walk function from getting a chance to walk the subforms
  1174. ;;; of the form.  This is almost never what you want, since it destroys the
  1175. ;;; equivalence between this nested-walk-form function and two seperate
  1176. ;;; walk-forms.
  1177. ;;;
  1178. (defun NESTED-WALK-FORM (whole
  1179.              form
  1180.              &optional environment
  1181.                    (walk-function
  1182.                      #'(lambda (subform context env)
  1183.                      (declare (ignore context env))
  1184.                      subform)))
  1185.   (if (eq whole (env-walk-form environment))
  1186.       (let ((outer-walk-function (env-walk-function environment)))
  1187.     (throw whole
  1188.       (walk-form
  1189.         form
  1190.         environment
  1191.         #'(lambda (f c e)
  1192.         ;; First loop to make sure the inner walk function
  1193.         ;; has done all it wants to do with this form.
  1194.         ;; Basically, what we are doing here is providing
  1195.         ;; the same contract walk-form-internal normally
  1196.         ;; provides to the inner walk function.
  1197.         (let ((inner-result nil)
  1198.               (inner-no-more-p nil)
  1199.               (outer-result nil)
  1200.               (outer-no-more-p nil))
  1201.           (loop
  1202.             (multiple-value-setq (inner-result inner-no-more-p)
  1203.                      (funcall walk-function f c e))
  1204.             (cond (inner-no-more-p (return))
  1205.               ((not (eq inner-result f)))
  1206.               ((not (consp inner-result)) (return))
  1207.               ((get-walker-template (car inner-result)) (return))
  1208.               (t
  1209.                (multiple-value-bind (expansion macrop)
  1210.                    (walker-environment-bind
  1211.                      (new-env e :walk-form inner-result)
  1212.                  (macroexpand-1 inner-result new-env))
  1213.                  (if macrop
  1214.                  (setq inner-result expansion)
  1215.                  (return)))))
  1216.             (setq f inner-result))
  1217.           (multiple-value-setq (outer-result outer-no-more-p)
  1218.                        (funcall outer-walk-function
  1219.                         inner-result
  1220.                         c
  1221.                         e))
  1222.           (values outer-result
  1223.               (and inner-no-more-p outer-no-more-p)))))))
  1224.       (walk-form form environment walk-function)))
  1225.  
  1226. ;;;
  1227. ;;; WALK-FORM-INTERNAL is the main driving function for the code walker. It
  1228. ;;; takes a form and the current context and walks the form calling itself or
  1229. ;;; the appropriate template recursively.
  1230. ;;;
  1231. ;;;   "It is recommended that a program-analyzing-program process a form
  1232. ;;;    that is a list whose car is a symbol as follows:
  1233. ;;;
  1234. ;;;     1. If the program has particular knowledge about the symbol,
  1235. ;;;        process the form using special-purpose code.  All of the
  1236. ;;;        standard special forms should fall into this category.
  1237. ;;;     2. Otherwise, if macro-function is true of the symbol apply
  1238. ;;;        either macroexpand or macroexpand-1 and start over.
  1239. ;;;     3. Otherwise, assume it is a function call. "
  1240. ;;;     
  1241.  
  1242. (defun walk-form-internal (form context env
  1243.                &aux newform newnewform
  1244.                 walk-no-more-p macrop
  1245.                 fn template)
  1246.   ;; First apply the walk-function to perform whatever translation
  1247.   ;; the user wants to this form.  If the second value returned
  1248.   ;; by walk-function is T then we don't recurse...
  1249.   (catch form
  1250.     (multiple-value-setq (newform walk-no-more-p)
  1251.       (funcall (env-walk-function env) form context env))
  1252.     (catch newform
  1253.       (cond (walk-no-more-p newform)
  1254.         ((not (eq form newform))
  1255.          (walk-form-internal newform context env))
  1256.         ((not (consp newform)) newform)
  1257.         ((setq template (get-walker-template (setq fn (car newform))))
  1258.          (if (symbolp template)
  1259.          (funcall template newform context env)
  1260.          (walk-template newform template context env)))
  1261.         (t
  1262.          (multiple-value-setq (newnewform macrop)
  1263.            (walker-environment-bind (new-env env :walk-form newform)
  1264.          (macroexpand-1 newform new-env)))
  1265.          (cond (macrop (walk-form-internal newnewform context env))
  1266.            ((and (symbolp fn)
  1267.              (not (fboundp fn))
  1268.              (special-form-p fn))
  1269.             (error
  1270.               "~S is a special form, not defined in the CommonLisp.~%~
  1271.                        manual This code walker doesn't know how to walk it.~%~
  1272.                        Define a template for this special form and try again."
  1273.               fn))
  1274.            (t
  1275.             ;; Otherwise, walk the form as if its just a standard 
  1276.             ;; functioncall using a template for standard function
  1277.             ;; call.
  1278.             (walk-template
  1279.               newnewform '(call repeat (eval)) context env))))))))
  1280.  
  1281. (defun walk-template (form template context env)
  1282.   (if (atom template)
  1283.       (ecase template
  1284.         ((EVAL FUNCTION TEST EFFECT RETURN)
  1285.          (walk-form-internal form :EVAL env))
  1286.         ((QUOTE NIL) form)
  1287.         (SET
  1288.           (walk-form-internal form :SET env))
  1289.         ((LAMBDA CALL)
  1290.      (cond ((symbolp form) form)
  1291.            #+Lispm
  1292.            ((sys:validate-function-spec form) form)
  1293.            (t (walk-form-internal form context env)))))
  1294.       (case (car template)
  1295.         (REPEAT
  1296.           (walk-template-handle-repeat form
  1297.                                        (cdr template)
  1298.                        ;; For the case where nothing happens
  1299.                        ;; after the repeat optimize out the
  1300.                        ;; call to length.
  1301.                        (if (null (cddr template))
  1302.                        ()
  1303.                        (nthcdr (- (length form)
  1304.                               (length
  1305.                             (cddr template)))
  1306.                            form))
  1307.                                        context
  1308.                        env))
  1309.         (IF
  1310.       (walk-template form
  1311.              (if (if (listp (cadr template))
  1312.                  (eval (cadr template))
  1313.                  (funcall (cadr template) form))
  1314.                  (caddr template)
  1315.                  (cadddr template))
  1316.              context
  1317.              env))
  1318.         (REMOTE
  1319.           (walk-template form (cadr template) context env))
  1320.         (otherwise
  1321.           (cond ((atom form) form)
  1322.                 (t (recons form
  1323.                            (walk-template
  1324.                  (car form) (car template) context env)
  1325.                            (walk-template
  1326.                  (cdr form) (cdr template) context env))))))))
  1327.  
  1328. (defun walk-template-handle-repeat (form template stop-form context env)
  1329.   (if (eq form stop-form)
  1330.       (walk-template form (cdr template) context env)
  1331.       (walk-template-handle-repeat-1 form
  1332.                      template
  1333.                      (car template)
  1334.                      stop-form
  1335.                      context
  1336.                      env)))
  1337.  
  1338. (defun walk-template-handle-repeat-1 (form template repeat-template
  1339.                        stop-form context env)
  1340.   (cond ((null form) ())
  1341.         ((eq form stop-form)
  1342.          (if (null repeat-template)
  1343.              (walk-template stop-form (cdr template) context env)       
  1344.              (error "While handling repeat:
  1345.                      ~%~Ran into stop while still in repeat template.")))
  1346.         ((null repeat-template)
  1347.          (walk-template-handle-repeat-1
  1348.        form template (car template) stop-form context env))
  1349.         (t
  1350.          (recons form
  1351.                  (walk-template (car form) (car repeat-template) context env)
  1352.                  (walk-template-handle-repeat-1 (cdr form)
  1353.                         template
  1354.                         (cdr repeat-template)
  1355.                         stop-form
  1356.                         context
  1357.                         env)))))
  1358.  
  1359. (defun walk-repeat-eval (form env)
  1360.   (and form
  1361.        (recons form
  1362.            (walk-form-internal (car form) :eval env)
  1363.            (walk-repeat-eval (cdr form) env))))
  1364.  
  1365. (defun recons (x car cdr)
  1366.   (if (or (not (eq (car x) car))
  1367.           (not (eq (cdr x) cdr)))
  1368.       (cons car cdr)
  1369.       x))
  1370.  
  1371. (defun relist (x &rest args)
  1372.   (relist-internal x args nil))
  1373.  
  1374. (defun relist* (x &rest args)
  1375.   (relist-internal x args 't))
  1376.  
  1377. (defun relist-internal (x args *p)
  1378.   (if (null (cdr args))
  1379.       (if *p (car args) (list (car args)))
  1380.       (recons x
  1381.           (car args)
  1382.           (relist-internal (cdr x) (cdr args) *p))))
  1383.  
  1384.  
  1385.   ;;   
  1386. ;;;;;; Special walkers
  1387.   ;;
  1388.  
  1389. (defun walk-declarations (body fn env
  1390.                    &optional doc-string-p declarations old-body
  1391.                    &aux (form (car body)) macrop new-form)
  1392.   (cond ((and (stringp form)            ;might be a doc string
  1393.               (cdr body)            ;isn't the returned value
  1394.               (null doc-string-p)        ;no doc string yet
  1395.               (null declarations))        ;no declarations yet
  1396.          (recons body
  1397.                  form
  1398.                  (walk-declarations (cdr body) fn env t)))
  1399.         ((and (listp form) (eq (car form) 'declare))
  1400.          ;; Got ourselves a real live declaration.  Record it, look for more.
  1401.          (dolist (declaration (cdr form))
  1402.        (let ((type (car declaration))
  1403.          (name (cadr declaration))
  1404.          (args (cddr declaration)))
  1405.          (if (member type *variable-declarations*)
  1406.          (note-declaration `(,type
  1407.                      ,(or (variable-lexical-p name env) name)
  1408.                      ,.args)
  1409.                    env)
  1410.          (note-declaration declaration env))
  1411.          (push declaration declarations)))
  1412.          (recons body
  1413.                  form
  1414.                  (walk-declarations
  1415.            (cdr body) fn env doc-string-p declarations)))
  1416.         ((and form
  1417.           (listp form)
  1418.           (null (get-walker-template (car form)))
  1419.           (progn
  1420.         (multiple-value-setq (new-form macrop)
  1421.                      (macroexpand-1 form env))
  1422.         macrop))
  1423.      ;; This form was a call to a macro.  Maybe it expanded
  1424.      ;; into a declare?  Recurse to find out.
  1425.      (walk-declarations (recons body new-form (cdr body))
  1426.                 fn env doc-string-p declarations
  1427.                 (or old-body body)))
  1428.     (t
  1429.      ;; Now that we have walked and recorded the declarations,
  1430.      ;; call the function our caller provided to expand the body.
  1431.      ;; We call that function rather than passing the real-body
  1432.      ;; back, because we are RECONSING up the new body.
  1433.      (funcall fn (or old-body body) env))))
  1434.  
  1435.  
  1436. (defun walk-unexpected-declare (form context env)
  1437.   (declare (ignore context env))
  1438.   (warn "Encountered declare ~S in a place where a declare was not expected."
  1439.     form)
  1440.   form)
  1441.  
  1442. (defun walk-arglist (arglist context env &optional (destructuringp nil)
  1443.                      &aux arg)
  1444.   (cond ((null arglist) ())
  1445.         ((symbolp (setq arg (car arglist)))
  1446.          (or (member arg lambda-list-keywords)
  1447.              (note-lexical-binding arg env))
  1448.          (recons arglist
  1449.                  arg
  1450.                  (walk-arglist (cdr arglist)
  1451.                                context
  1452.                    env
  1453.                                (and destructuringp
  1454.                     (not (member arg
  1455.                          lambda-list-keywords))))))
  1456.         ((consp arg)
  1457.          (prog1 (if destructuringp
  1458.                     (walk-arglist arg context env destructuringp)
  1459.                     (recons arglist
  1460.                             (relist* arg
  1461.                                      (car arg)
  1462.                                      (walk-form-internal (cadr arg) :eval env)
  1463.                                      (cddr arg))
  1464.                             (walk-arglist (cdr arglist) context env nil)))
  1465.                 (if (symbolp (car arg))
  1466.                     (note-lexical-binding (car arg) env)
  1467.                     (note-lexical-binding (cadar arg) env))
  1468.                 (or (null (cddr arg))
  1469.                     (not (symbolp (caddr arg)))
  1470.                     (note-lexical-binding (caddr arg) env))))
  1471.           (t
  1472.        (error "Can't understand something in the arglist ~S" arglist))))
  1473.  
  1474. (defun walk-let (form context env)
  1475.   (walk-let/let* form context env nil))
  1476.  
  1477. (defun walk-let* (form context env)
  1478.   (walk-let/let* form context env t))
  1479.  
  1480. (defun walk-prog (form context env)
  1481.   (walk-prog/prog* form context env nil))
  1482.  
  1483. (defun walk-prog* (form context env)
  1484.   (walk-prog/prog* form context env t))
  1485.  
  1486. (defun walk-do (form context env)
  1487.   (walk-do/do* form context env nil))
  1488.  
  1489. (defun walk-do* (form context env)
  1490.   (walk-do/do* form context env t))
  1491.  
  1492. (defun walk-let/let* (form context old-env sequentialp)
  1493.   (walker-environment-bind (new-env old-env)
  1494.     (let* ((let/let* (car form))
  1495.        (bindings (cadr form))
  1496.        (body (cddr form))
  1497.        (walked-bindings 
  1498.          (walk-bindings-1 bindings
  1499.                   old-env
  1500.                   new-env
  1501.                   context
  1502.                   sequentialp))
  1503.        (walked-body
  1504.          (walk-declarations body #'walk-repeat-eval new-env)))
  1505.       (relist*
  1506.     form let/let* walked-bindings walked-body))))
  1507.  
  1508. (defun walk-prog/prog* (form context old-env sequentialp)
  1509.   (walker-environment-bind (new-env old-env)
  1510.     (let* ((possible-block-name (second form))
  1511.        (blocked-prog (and (symbolp possible-block-name)
  1512.                   (not (eq possible-block-name 'nil)))))
  1513.       (multiple-value-bind (let/let* block-name bindings body)
  1514.       (if blocked-prog
  1515.           (values (car form) (cadr form) (caddr form) (cdddr form))
  1516.           (values (car form) nil         (cadr  form) (cddr  form)))
  1517.     (let* ((walked-bindings 
  1518.          (walk-bindings-1 bindings
  1519.                   old-env
  1520.                   new-env
  1521.                   context
  1522.                   sequentialp))
  1523.            (walked-body
  1524.          (walk-declarations 
  1525.            body
  1526.            #'(lambda (real-body real-env)
  1527.                (walk-tagbody-1 real-body context real-env))
  1528.            new-env)))
  1529.       (if block-name
  1530.           (relist*
  1531.         form let/let* block-name walked-bindings walked-body)
  1532.           (relist*
  1533.         form let/let* walked-bindings walked-body)))))))
  1534.  
  1535. (defun walk-do/do* (form context old-env sequentialp)
  1536.   (walker-environment-bind (new-env old-env)
  1537.     (let* ((do/do* (car form))
  1538.        (bindings (cadr form))
  1539.        (end-test (caddr form))
  1540.        (body (cdddr form))
  1541.        (walked-bindings (walk-bindings-1 bindings
  1542.                          old-env
  1543.                          new-env
  1544.                          context
  1545.                          sequentialp))
  1546.        (walked-body
  1547.          (walk-declarations body #'walk-repeat-eval new-env)))
  1548.       (relist* form
  1549.            do/do*
  1550.            (walk-bindings-2 bindings walked-bindings context new-env)
  1551.            (walk-template end-test '(test repeat (eval)) context new-env)
  1552.            walked-body))))
  1553.  
  1554. (defun walk-let-if (form context env)
  1555.   (let ((test (cadr form))
  1556.     (bindings (caddr form))
  1557.     (body (cdddr form)))
  1558.     (walk-form-internal
  1559.       `(let ()
  1560.      (declare (special ,@(mapcar #'(lambda (x) (if (listp x) (car x) x))
  1561.                      bindings)))
  1562.      (flet ((.let-if-dummy. () ,@body))
  1563.        (if ,test
  1564.            (let ,bindings (.let-if-dummy.))
  1565.            (.let-if-dummy.))))
  1566.       context
  1567.       env)))
  1568.  
  1569. (defun walk-multiple-value-bind (form context old-env)
  1570.   (walker-environment-bind (new-env old-env)
  1571.     (let* ((mvb (car form))
  1572.        (bindings (cadr form))
  1573.        (mv-form (walk-template (caddr form) 'eval context old-env))
  1574.        (body (cdddr form))
  1575.        walked-bindings
  1576.        (walked-body
  1577.          (walk-declarations 
  1578.            body
  1579.            #'(lambda (real-body real-env)
  1580.            (setq walked-bindings
  1581.              (walk-bindings-1 bindings
  1582.                       old-env
  1583.                       new-env
  1584.                       context
  1585.                       nil))
  1586.            (walk-repeat-eval real-body real-env))
  1587.            new-env)))
  1588.       (relist* form mvb walked-bindings mv-form walked-body))))
  1589.  
  1590. (defun walk-bindings-1 (bindings old-env new-env context sequentialp)
  1591.   (and bindings
  1592.        (let ((binding (car bindings)))
  1593.          (recons bindings
  1594.                  (if (symbolp binding)
  1595.                      (prog1 binding
  1596.                             (note-lexical-binding binding new-env))
  1597.                      (prog1 (relist* binding
  1598.                      (car binding)
  1599.                      (walk-form-internal (cadr binding)
  1600.                              context
  1601.                              (if sequentialp
  1602.                                  new-env
  1603.                                  old-env))
  1604.                      (cddr binding))    ;save cddr for DO/DO*
  1605.                                 ;it is the next value
  1606.                                 ;form. Don't walk it
  1607.                                 ;now though.
  1608.                             (note-lexical-binding (car binding) new-env)))
  1609.                  (walk-bindings-1 (cdr bindings)
  1610.                   old-env
  1611.                   new-env
  1612.                   context
  1613.                   sequentialp)))))
  1614.  
  1615. (defun walk-bindings-2 (bindings walked-bindings context env)
  1616.   (and bindings
  1617.        (let ((binding (car bindings))
  1618.              (walked-binding (car walked-bindings)))
  1619.          (recons bindings
  1620.          (if (symbolp binding)
  1621.              binding
  1622.              (relist* binding
  1623.                   (car walked-binding)
  1624.                   (cadr walked-binding)
  1625.                   (walk-template (cddr binding)
  1626.                          '(eval)
  1627.                          context
  1628.                          env)))         
  1629.                  (walk-bindings-2 (cdr bindings)
  1630.                   (cdr walked-bindings)
  1631.                   context
  1632.                   env)))))
  1633.  
  1634. (defun walk-lambda (form context old-env)
  1635.   (walker-environment-bind (new-env old-env)
  1636.     (let* ((arglist (cadr form))
  1637.            (body (cddr form))
  1638.            (walked-arglist (walk-arglist arglist context new-env))
  1639.            (walked-body
  1640.              (walk-declarations body #'walk-repeat-eval new-env)))
  1641.       (relist* form
  1642.                (car form)
  1643.            walked-arglist
  1644.                walked-body))))
  1645.  
  1646. (defun walk-named-lambda (form context old-env)
  1647.   (walker-environment-bind (new-env old-env)
  1648.     (let* ((name (cadr form))
  1649.        (arglist (caddr form))
  1650.            (body (cdddr form))
  1651.            (walked-arglist (walk-arglist arglist context new-env))
  1652.            (walked-body
  1653.              (walk-declarations body #'walk-repeat-eval new-env)))
  1654.       (relist* form
  1655.                (car form)
  1656.            name
  1657.            walked-arglist
  1658.                walked-body))))  
  1659.  
  1660. (defun walk-tagbody (form context env)
  1661.   (recons form (car form) (walk-tagbody-1 (cdr form) context env)))
  1662.  
  1663. (defun walk-tagbody-1 (form context env)
  1664.   (and form
  1665.        (recons form
  1666.                (walk-form-internal (car form)
  1667.                    (if (symbolp (car form)) 'quote context)
  1668.                    env)
  1669.                (walk-tagbody-1 (cdr form) context env))))
  1670.  
  1671. (defun walk-compiler-let (form context old-env)
  1672.   (declare (ignore context))
  1673.   (let ((vars ())
  1674.     (vals ()))
  1675.     (dolist (binding (cadr form))
  1676.       (cond ((symbolp binding) (push binding vars) (push nil vals))
  1677.         (t
  1678.          (push (car binding) vars)
  1679.          (push (eval (cadr binding)) vals))))
  1680.     (relist* form
  1681.          (car form)
  1682.          (cadr form)
  1683.          (progv vars vals (walk-repeat-eval (cddr form) old-env)))))
  1684.  
  1685. (defun walk-macrolet (form context old-env)
  1686.   (walker-environment-bind (macro-env
  1687.                 nil
  1688.                 :walk-function (env-walk-function old-env))
  1689.     (labels ((walk-definitions (definitions)
  1690.            (and definitions
  1691.             (let ((definition (car definitions)))
  1692.               (recons definitions
  1693.                               (relist* definition
  1694.                                        (car definition)
  1695.                                        (walk-arglist (cadr definition)
  1696.                              context
  1697.                              macro-env
  1698.                              t)
  1699.                                        (walk-declarations (cddr definition)
  1700.                               #'walk-repeat-eval
  1701.                               macro-env))
  1702.                   (walk-definitions (cdr definitions)))))))
  1703.       (with-new-definition-in-environment (new-env old-env form)
  1704.     (relist* form
  1705.          (car form)
  1706.          (walk-definitions (cadr form))
  1707.          (walk-declarations (cddr form)
  1708.                     #'walk-repeat-eval
  1709.                     new-env))))))
  1710.  
  1711. (defun walk-flet (form context old-env)
  1712.   (labels ((walk-definitions (definitions)
  1713.          (if (null definitions)
  1714.          ()
  1715.          (recons definitions
  1716.              (walk-lambda (car definitions) context old-env)
  1717.              (walk-definitions (cdr definitions))))))
  1718.     (recons form
  1719.         (car form)
  1720.         (recons (cdr form)
  1721.             (walk-definitions (cadr form))
  1722.             (with-new-definition-in-environment (new-env old-env form)
  1723.               (walk-declarations (cddr form)
  1724.                      #'walk-repeat-eval
  1725.                      new-env))))))
  1726.  
  1727. (defun walk-labels (form context old-env)
  1728.   (with-new-definition-in-environment (new-env old-env form)
  1729.     (labels ((walk-definitions (definitions)
  1730.            (if (null definitions)
  1731.            ()
  1732.            (recons definitions
  1733.                (walk-lambda (car definitions) context new-env)
  1734.                (walk-definitions (cdr definitions))))))
  1735.       (recons form
  1736.           (car form)
  1737.           (recons (cdr form)
  1738.               (walk-definitions (cadr form))
  1739.               (walk-declarations (cddr form)
  1740.                      #'walk-repeat-eval
  1741.                      new-env))))))
  1742.  
  1743. (defun walk-if (form context env)
  1744.   (let ((predicate (cadr form))
  1745.     (arm1 (caddr form))
  1746.     (arm2 
  1747.       (if (cddddr form)
  1748.           (progn
  1749.         (warn "In the form:~%~S~%~
  1750.                        IF only accepts three arguments, you are using ~D.~%~
  1751.                        It is true that some Common Lisps support this, but ~
  1752.                        it is not~%~
  1753.                        truly legal Common Lisp.  For now, this code ~
  1754.                        walker is interpreting ~%~
  1755.                        the extra arguments as extra else clauses. ~
  1756.                        Even if this is what~%~
  1757.                        you intended, you should fix your source code."
  1758.               form
  1759.               (length (cdr form)))
  1760.         (cons 'progn (cdddr form)))
  1761.           (cadddr form))))
  1762.     (relist form
  1763.         'if
  1764.         (walk-form-internal predicate context env)
  1765.         (walk-form-internal arm1 context env)
  1766.         (walk-form-internal arm2 context env))))
  1767.  
  1768.  
  1769. ;;;
  1770. ;;; Tests tests tests
  1771. ;;;
  1772.  
  1773. #|
  1774. ;;; 
  1775. ;;; Here are some examples of the kinds of things you should be able to do
  1776. ;;; with your implementation of the macroexpansion environment hacking
  1777. ;;; mechanism.
  1778. ;;; 
  1779. ;;; with-lexical-macros is kind of like macrolet, but it only takes names
  1780. ;;; of the macros and actual macroexpansion functions to use to macroexpand
  1781. ;;; them.  The win about that is that for macros which want to wrap several
  1782. ;;; macrolets around their body, they can do this but have the macroexpansion
  1783. ;;; functions be compiled.  See the WITH-RPUSH example.
  1784. ;;;
  1785. ;;; If the implementation had a special way of communicating the augmented
  1786. ;;; environment back to the evaluator that would be totally great.  It would
  1787. ;;; mean that we could just augment the environment then pass control back
  1788. ;;; to the implementations own compiler or interpreter.  We wouldn't have
  1789. ;;; to call the actual walker.  That would make this much faster.  Since the
  1790. ;;; principal client of this is defmethod it would make compiling defmethods
  1791. ;;; faster and that would certainly be a win.
  1792. ;;;
  1793. (defmacro with-lexical-macros (macros &body body &environment old-env)
  1794.   (with-augmented-environment (new-env old-env :macros macros)
  1795.     (walk-form (cons 'progn body) :environment new-env)))
  1796.  
  1797. (defun expand-rpush (form env)
  1798.   `(push ,(caddr form) ,(cadr form)))
  1799.  
  1800. (defmacro with-rpush (&body body)
  1801.   `(with-lexical-macros ,(list (list 'rpush #'expand-rpush)) ,@body))
  1802.  
  1803.  
  1804. ;;;
  1805. ;;; Unfortunately, I don't have an automatic tester for the walker.  
  1806. ;;; Instead there is this set of test cases with a description of
  1807. ;;; how each one should go.
  1808. ;;; 
  1809. (defmacro take-it-out-for-a-test-walk (form)
  1810.   `(take-it-out-for-a-test-walk-1 ',form))
  1811.  
  1812. (defun take-it-out-for-a-test-walk-1 (form)
  1813.   (terpri)
  1814.   (terpri)
  1815.   (let ((copy-of-form (copy-tree form))
  1816.     (result (walk-form form nil
  1817.           #'(lambda (x y env)
  1818.               (format t "~&Form: ~S ~3T Context: ~A" x y)
  1819.               (when (symbolp x)
  1820.             (let ((lexical (variable-lexical-p x env))
  1821.                   (special (variable-special-p x env)))
  1822.               (when lexical
  1823.                 (format t ";~3T")
  1824.                 (format t "lexically bound"))
  1825.               (when special
  1826.                 (format t ";~3T")
  1827.                 (format t "declared special"))
  1828.               (when (boundp x)
  1829.                 (format t ";~3T")
  1830.                 (format t "bound: ~S " (eval x)))))
  1831.               x))))
  1832.     (cond ((not (equal result copy-of-form))
  1833.        (format t "~%Warning: Result not EQUAL to copy of start."))
  1834.       ((not (eq result form))
  1835.        (format t "~%Warning: Result not EQ to copy of start.")))
  1836.     (pprint result)
  1837.     result))
  1838.  
  1839. (defmacro foo (&rest ignore) ''global-foo)
  1840.  
  1841. (defmacro bar (&rest ignore) ''global-bar)
  1842.  
  1843. (take-it-out-for-a-test-walk (list arg1 arg2 arg3))
  1844. (take-it-out-for-a-test-walk (list (cons 1 2) (list 3 4 5)))
  1845.  
  1846. (take-it-out-for-a-test-walk (progn (foo) (bar 1)))
  1847.  
  1848. (take-it-out-for-a-test-walk (block block-name a b c))
  1849. (take-it-out-for-a-test-walk (block block-name (list a) b c))
  1850.  
  1851. (take-it-out-for-a-test-walk (catch catch-tag (list a) b c))
  1852. ;;;
  1853. ;;; This is a fairly simple macrolet case.  While walking the body of the
  1854. ;;; macro, x should be lexically bound. In the body of the macrolet form
  1855. ;;; itself, x should not be bound.
  1856. ;;; 
  1857. (take-it-out-for-a-test-walk
  1858.   (macrolet ((foo (x) (list x) ''inner))
  1859.     x
  1860.     (foo 1)))
  1861.  
  1862. ;;;
  1863. ;;; A slightly more complex macrolet case.  In the body of the macro x
  1864. ;;; should not be lexically bound.  In the body of the macrolet form itself
  1865. ;;; x should be bound.  Note that THIS CASE WILL CAUSE AN ERROR when it
  1866. ;;; tries to macroexpand the call to foo.
  1867. ;;; 
  1868. (take-it-out-for-a-test-walk
  1869.      (let ((x 1))
  1870.        (macrolet ((foo () (list x) ''inner))
  1871.      x
  1872.      (foo))))
  1873.  
  1874. ;;;
  1875. ;;; A truly hairy use of compiler-let and macrolet.  In the body of the
  1876. ;;; macro x should not be lexically bound.  In the body of the macrolet
  1877. ;;; itself x should not be lexically bound.  But the macro should expand
  1878. ;;; into 1.
  1879. ;;; 
  1880. (take-it-out-for-a-test-walk
  1881.   (compiler-let ((x 1))
  1882.     (let ((x 2))
  1883.       (macrolet ((foo () x))
  1884.     x
  1885.     (foo)))))
  1886.  
  1887.  
  1888. (take-it-out-for-a-test-walk
  1889.   (flet ((foo (x) (list x y))
  1890.      (bar (x) (list x y)))
  1891.     (foo 1)))
  1892.  
  1893. (take-it-out-for-a-test-walk
  1894.   (let ((y 2))
  1895.     (flet ((foo (x) (list x y))
  1896.        (bar (x) (list x y)))
  1897.       (foo 1))))
  1898.  
  1899. (take-it-out-for-a-test-walk
  1900.   (labels ((foo (x) (bar x))
  1901.        (bar (x) (foo x)))
  1902.     (foo 1)))
  1903.  
  1904. (take-it-out-for-a-test-walk
  1905.   (flet ((foo (x) (foo x)))
  1906.     (foo 1)))
  1907.  
  1908. (take-it-out-for-a-test-walk
  1909.   (flet ((foo (x) (foo x)))
  1910.     (flet ((bar (x) (foo x)))
  1911.       (bar 1))))
  1912.  
  1913. (take-it-out-for-a-test-walk (compiler-let ((a 1) (b 2)) (foo a) b))
  1914. (take-it-out-for-a-test-walk (prog () (declare (special a b))))
  1915. (take-it-out-for-a-test-walk (let (a b c)
  1916.                                (declare (special a b))
  1917.                                (foo a) b c))
  1918. (take-it-out-for-a-test-walk (let (a b c)
  1919.                                (declare (special a) (special b))
  1920.                                (foo a) b c))
  1921. (take-it-out-for-a-test-walk (let (a b c)
  1922.                                (declare (special a))
  1923.                                (declare (special b))
  1924.                                (foo a) b c))
  1925. (take-it-out-for-a-test-walk (let (a b c)
  1926.                                (declare (special a))
  1927.                                (declare (special b))
  1928.                                (let ((a 1))
  1929.                                  (foo a) b c)))
  1930. (take-it-out-for-a-test-walk (eval-when ()
  1931.                                a
  1932.                                (foo a)))
  1933. (take-it-out-for-a-test-walk (eval-when (eval when load)
  1934.                                a
  1935.                                (foo a)))
  1936.  
  1937. (take-it-out-for-a-test-walk (multiple-value-bind (a b) (foo a b) (list a b)))
  1938. (take-it-out-for-a-test-walk (multiple-value-bind (a b)
  1939.                  (foo a b)
  1940.                    (declare (special a))
  1941.                    (list a b)))
  1942. (take-it-out-for-a-test-walk (progn (function foo)))
  1943. (take-it-out-for-a-test-walk (progn a b (go a)))
  1944. (take-it-out-for-a-test-walk (if a b c))
  1945. (take-it-out-for-a-test-walk (if a b))
  1946. (take-it-out-for-a-test-walk ((lambda (a b) (list a b)) 1 2))
  1947. (take-it-out-for-a-test-walk ((lambda (a b) (declare (special a)) (list a b))
  1948.                   1 2))
  1949. (take-it-out-for-a-test-walk (let ((a a) (b a) (c b)) (list a b c)))
  1950. (take-it-out-for-a-test-walk (let* ((a a) (b a) (c b)) (list a b c)))
  1951. (take-it-out-for-a-test-walk (let ((a a) (b a) (c b))
  1952.                                (declare (special a b))
  1953.                                (list a b c)))
  1954. (take-it-out-for-a-test-walk (let* ((a a) (b a) (c b))
  1955.                                (declare (special a b))
  1956.                                (list a b c)))
  1957. (take-it-out-for-a-test-walk (let ((a 1) (b 2))
  1958.                                (foo bar)
  1959.                                (declare (special a))
  1960.                                (foo a b)))
  1961. (take-it-out-for-a-test-walk (multiple-value-call #'foo a b c))
  1962. (take-it-out-for-a-test-walk (multiple-value-prog1 a b c))
  1963. (take-it-out-for-a-test-walk (progn a b c))
  1964. (take-it-out-for-a-test-walk (progv vars vals a b c))
  1965. (take-it-out-for-a-test-walk (quote a))
  1966. (take-it-out-for-a-test-walk (return-from block-name a b c))
  1967. (take-it-out-for-a-test-walk (setq a 1))
  1968. (take-it-out-for-a-test-walk (setq a (foo 1) b (bar 2) c 3))
  1969. (take-it-out-for-a-test-walk (tagbody a b c (go a)))
  1970. (take-it-out-for-a-test-walk (the foo (foo-form a b c)))
  1971. (take-it-out-for-a-test-walk (throw tag-form a))
  1972. (take-it-out-for-a-test-walk (unwind-protect (foo a b) d e f))
  1973.  
  1974. (defmacro flet-1 (a b) ''outer)
  1975. (defmacro labels-1 (a b) ''outer)
  1976.  
  1977. (take-it-out-for-a-test-walk
  1978.   (flet ((flet-1 (a b) () (flet-1 a b) (list a b)))
  1979.     (flet-1 1 2)
  1980.     (foo 1 2)))
  1981. (take-it-out-for-a-test-walk
  1982.   (labels ((label-1 (a b) () (label-1 a b)(list a b)))
  1983.     (label-1 1 2)
  1984.     (foo 1 2)))
  1985. (take-it-out-for-a-test-walk (macrolet ((macrolet-1 (a b) (list a b)))
  1986.                                (macrolet-1 a b)
  1987.                                (foo 1 2)))
  1988.  
  1989. (take-it-out-for-a-test-walk (macrolet ((foo (a) `(inner-foo-expanded ,a)))
  1990.                                (foo 1)))
  1991.  
  1992. (take-it-out-for-a-test-walk (progn (bar 1)
  1993.                                     (macrolet ((bar (a)
  1994.                          `(inner-bar-expanded ,a)))
  1995.                                       (bar 2))))
  1996.  
  1997. (take-it-out-for-a-test-walk (progn (bar 1)
  1998.                                     (macrolet ((bar (s)
  1999.                          (bar s)
  2000.                          `(inner-bar-expanded ,s)))
  2001.                                       (bar 2))))
  2002.  
  2003. (take-it-out-for-a-test-walk (cond (a b)
  2004.                                    ((foo bar) a (foo a))))
  2005.  
  2006.  
  2007. (let ((the-lexical-variables ()))
  2008.   (walk-form '(let ((a 1) (b 2))
  2009.         #'(lambda (x) (list a b x y)))
  2010.          ()
  2011.          #'(lambda (form context env)
  2012.          (when (and (symbolp form)
  2013.                 (variable-lexical-p form env))
  2014.            (push form the-lexical-variables))
  2015.          form))
  2016.   (or (and (= (length the-lexical-variables) 3)
  2017.        (member 'a the-lexical-variables)
  2018.        (member 'b the-lexical-variables)
  2019.        (member 'x the-lexical-variables))
  2020.       (error "Walker didn't do lexical variables of a closure properly.")))
  2021.     
  2022. |#
  2023.  
  2024. ()
  2025.